/*
 * Copyright 2008 Nathan C Jones
 * 
 * This file is part of Fivehundred.
 * 
 * Fivehundred is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Fivehundred is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Fivehundred. If not, see <http://www.gnu.org/licenses/>. 
 */

package com.googlecode.fivehundred.ui;

import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
 * <p>
 * A graphical component which can be painted onto a shared graphics canvas and
 * can receive mouse events.
 * </p>
 * <p>
 * Graphical components can be rotated. The centre of rotation for a graphical
 * component is the same as the component's position relative to its parent. For
 * simplicity and consistency both the centre of rotation and the position
 * offset of a graphical component should be located at the <em>centre</em> of
 * the component. In other words, setting the position of a graphical component
 * should set the position of the <em>centre</em> of the component, and
 * rotating the component should rotate it about the same point.
 * </p>
 * TODO any changes to the state of a component need to cause a repaint of the
 * parent.
 * 
 * @author Nathan C Jones
 */
public interface GraphicalComponent {

	/**
	 * Causes the component to paint itself onto the given graphics. A component
	 * may not know its own position within a canvas so it must be given an
	 * offset coordinate when it is painted.
	 * 
	 * @param g the graphics to paint the component onto.
	 * @param x the horizontal offset in of the parent component in pixels from
	 *        the left edge of the root container.
	 * @param y the vertical offset of the parent component in pixels from the
	 *        top edge of the root container.
	 * @param angle the angle if the parent component.
	 */
	void paint(Graphics2D g, int x, int y, double angle);

	/**
	 * Determine if the component contains the given point. A component may not
	 * know its own position within a canvas so it must be given an offset when
	 * determining if it contains some point.
	 * 
	 * @param p the point which might be contained within the bounds of the
	 *        component.
	 * @param x the horizontal offset of the parent component in pixels from the
	 *        left edge of the root container.
	 * @param y the vertical offset in pixels of the parent component from the
	 *        top edge of the root container.
	 * @param angle the angle of the parent component.
	 * @return true if the given point falls within the component when the
	 *         component is offset by the given coordinates.
	 */
	boolean contains(Point p, int x, int y, double angle);

	/**
	 * Add a mouse listener to the component so it receives notifications of
	 * mouse events. If the listener was already registered with the component
	 * then no action is taken.
	 * 
	 * @param listener the listener to receive notifications of mouse events.
	 */
	void addMouseListener(MouseListener listener);

	/**
	 * Remove a mouse listener from the component so it no longer receives
	 * notifications of mouse events. If the listener was not registered with the
	 * component then no action is taken.
	 * 
	 * @param listener the listener to no longer receive mouse events.
	 */
	void removeMouseListener(MouseListener listener);

	/**
	 * Cause the component to notify all of its mouse listeners of the given
	 * mouse event.
	 * 
	 * @param event the mouse event which has occured on the component.
	 * @throws IllegalArgumentException if the event is <code>null</code>.
	 */
	void processMouseEvent(MouseEvent event);

	/**
	 * Get the position of the <em>centre</em> of the graphical component
	 * relative to its parent.
	 * 
	 * @return the component's position.
	 */
	Point getPosition();

	/**
	 * Set the position of the <em>centre</em> of the graphical component.
	 * 
	 * @param x the horizontal position of the component relative to its parent
	 *        in pixels.
	 * @param y the vertical position of the component relative to its parent in
	 *        pixels.
	 */
	void setPosition(int x, int y);

	/**
	 * Get the position of the component relative to the origin of the canvas.
	 * 
	 * @return the component's position relative to the origin of the root
	 *         canvas.
	 * @throws IllegalStateException if there is no path to a root canvas from
	 *         the component.
	 */
	Point getAbsolutePosition();

	/**
	 * Get the angle of the graphical component in radians.
	 * 
	 * @return the current angle of the component.
	 */
	double getAngle();

	/**
	 * Set the angle of the graphical component in radians. The component will be
	 * rotated about its centre point by this amount.
	 * 
	 * @param angle the new angle of the component.
	 */
	void setAngle(double angle);

	/**
	 * Get the angle of the component relative to the root canvas.
	 * 
	 * @return the component's absolute angle relative to the root canvas.
	 * @throws IllegalStateException if there is no path to a root canvas from
	 *         the component.
	 */
	double getAbsoluteAngle();

	/**
	 * Get the parent of the graphical component.
	 * 
	 * @return the graphical component's parent, or <code>null</code> if there
	 *         is none.
	 */
	CompositeGraphicalComponent getParent();

	/**
	 * Set the parent of the component.
	 * 
	 * @param parent the new parent.
	 */
	void setParent(CompositeGraphicalComponent parent);
}
